// GerikSpells.cpp
// A spell interface for Civ4 written by Gerikes
// This is a singleton class

#include "CvGameCoreDLL.h"
#include "GerikSpellsPythonIFace.h"
#include "CvGameCoreUtils.h"
#include "CvGlobals.h"
#include "CvInfos.h"
#include "CvGameAI.h"
#include "CvSelectionGroup.h"
#include "CyArgsList.h"
#include "CvDLLPythonIFaceBase.h"
#include "CvDLLInterfaceIFaceBase.h"
#include "CvDLLWidgetData.h"
#include "CvUnit.h"
#include "CvPlayerAI.h" // For GET_PLAYER


#include "CySelectionGroup.h"
#include "CyUnit.h"
#include "CyPlot.h"

#include <cmath>


const static TCHAR* CAN_GROUP_CAST_FUNC_NAME = "canGroupCast";
const static TCHAR* HANDLE_ACTION_BUTTON_CLICK_FUNC_NAME = "handleActionButtonClick";
const static TCHAR* START_SPELL_RESULTS_FUNC_NAME = "startSpellResults";
const static TCHAR* CONTINUE_SPELL_RESULTS_FUNC_NAME = "continueSpellResults";
const static TCHAR* CLEANUP_SPELL_FUNC_NAME = "cleanupSpell";
const static TCHAR* PARSE_TARGET_INFO = "parseTargetInfo";
const static TCHAR* GET_SPELL_HELP_TEXT = "getHelpText";
const static TCHAR* GET_SPELL_UNIT_HELP_TEXT = "getUnitHelpText";


GerikSpellsPythonIFace::GerikSpellsPythonIFace()
{

}

GerikSpellsPythonIFace::~GerikSpellsPythonIFace()
{
}

//----------------------------------------------------------------------------
//
//	FUNCTION:	GetInstance()
//
//	PURPOSE:	Get the instance of this class.
//
//----------------------------------------------------------------------------
GerikSpellsPythonIFace& GerikSpellsPythonIFace::GetInstance()
{
	static GerikSpellsPythonIFace gs_GerikSpellsPythonIFace;
	return gs_GerikSpellsPythonIFace;
}

bool GerikSpellsPythonIFace::canGroupCast(SpellTypes eSpell, CvSelectionGroup* pGroup, CvPlot* pCastPlot, bool bVisible)
{
	// Prevents showing cast buttons while moving.
	if (pGroup->isBusy())
	{
		return false;
	}

	CySelectionGroup* pyGroup = new CySelectionGroup(pGroup);
	CyPlot* pyPlot;
	if (pCastPlot != NULL)
	{
		pyPlot = new CyPlot(pCastPlot);
	}
	else
	{
		pyPlot = new CyPlot(pGroup->plot());
	}
		
	
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyPlot));
	argsList.add(bVisible);
	long lResult;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, CAN_GROUP_CAST_FUNC_NAME, argsList.makeFunctionArgs(), &lResult);
	delete pyGroup;
	delete pyPlot;

	return lResult;
}

void GerikSpellsPythonIFace::setSpellHelpText(CvWString &szBuffer, SpellTypes eSpell, CvSelectionGroup* pSelectedGroup, CvPlot* pPlot)
{
	CySelectionGroup* pyGroup = new CySelectionGroup(pSelectedGroup);
	CyPlot* pyPlot = new CyPlot(pPlot);
	
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyPlot));

	CvString szResult;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, GET_SPELL_HELP_TEXT, argsList.makeFunctionArgs(), &szResult);

	if (szResult.IsEmpty())
	{
		CvWString szWResult(GC.getSpellInfo(eSpell).getHelp());
		if (!isEmpty(szWResult))
		{
			szBuffer += CvWString::format(L"%s%s", NEWLINE, GC.getSpellInfo(eSpell).getHelp());
		}
	}
	else
	{
		// Convert into a wchar.
		// We couldn't get a wstring return, so the python side converts to utf8. We need to unconvert it...
		CvWString szWResult;
		GerikSpellsUtils::deencodeUtfToWideString(szResult, szWResult);
		
		wchar szTempBuffer[1024];
		swprintf(szTempBuffer, L"%s%s", NEWLINE, szWResult.GetCString());
		szBuffer += szTempBuffer;
	}
}

void GerikSpellsPythonIFace::parseTargetInfo(CvWidgetDataStruct& widgetDataStruct, CvWString& szBuffer)
{
	CyArgsList argsList;
	argsList.add(widgetDataStruct.m_iData1);
	argsList.add(widgetDataStruct.m_iData2);
	argsList.add(widgetDataStruct.m_bOption);
	CvString szResult;

	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, PARSE_TARGET_INFO, argsList.makeFunctionArgs(), &szResult);
	
	// Convert into a wchar.
	// We couldn't get a wstring return, so the python side converts to utf8. We need to unconvert it...
	CvWString szWResult;
	GerikSpellsUtils::deencodeUtfToWideString(szResult, szWResult);
	

	wchar szTempBuffer[1024];
	swprintf(szTempBuffer, L"%s", szWResult.GetCString());
	szBuffer += szTempBuffer;

	
}

void GerikSpellsPythonIFace::handleSpellActionClick(SpellTypes eSpell, CvSelectionGroup* pSelectedGroup, CvPlot* pCastPlot, bool bAlt, bool bShift, bool bCtrl)
{
	// Call the handler for an action click
	
	CySelectionGroup* pyGroup = new CySelectionGroup(pSelectedGroup);
	CyPlot* pyPlot = new CyPlot(pCastPlot);
		
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyPlot));
	argsList.add(bAlt);
	argsList.add(bShift);
	argsList.add(bCtrl);

	long lResult;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, HANDLE_ACTION_BUTTON_CLICK_FUNC_NAME, argsList.makeFunctionArgs(), &lResult);
	delete pyGroup;
	delete pyPlot;
}

void GerikSpellsPythonIFace::pushSpellMission(SpellTypes eSpell, int iData1, int iData2, int iFlags)
{
	bool bAlt = gDLL->altKey();
	bool bShift = gDLL->shiftKey();
	pushSpellMission(eSpell, iData1, iData2, iFlags, bAlt, bShift);
}

void GerikSpellsPythonIFace::pushSpellMission(SpellTypes eSpell, int iData1, int iData2, int iFlags, bool bAlt, bool bShift)
{
	int iEncodedFlags = GerikSpellsUtils::encodeFlagVariable(eSpell, iFlags);
	GC.getGameINLINE().selectionListGameNetMessage(GAMEMESSAGE_PUSH_MISSION, MISSION_SPELL, iData1, iData2, iEncodedFlags, bAlt, bShift);
}

bool GerikSpellsPythonIFace::startSpellResults(CvSelectionGroup* pSelectedGroup, int iData1, int iData2, int iEncodedFlags)
{
	// Call the python function to do scripts based on when a spell is "activated"
	CySelectionGroup* pyGroup = new CySelectionGroup(pSelectedGroup);

	// We had to pass eSpell and iData1 encoded into the MissionData data struct, so we'll deencode it now.
	SpellTypes eSpell = NO_SPELL;
	int iFlags = -1;
	GerikSpellsUtils::deencodeFlagVariable(iEncodedFlags, eSpell, iFlags);

	FAssertMsg(eSpell >= 0, "getSpellFromDataVariable computed an illegal spell type");
	FAssertMsg(eSpell < GC.getNumSpellInfos(), "getSpellFromDataVariable computed an illegal spell type");
	
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(iData1);
	argsList.add(iData2);
	argsList.add(iFlags);

	long lResult = 0;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, START_SPELL_RESULTS_FUNC_NAME, argsList.makeFunctionArgs(), &lResult);
	delete pyGroup;

	// This function returns true to delete the mission. The python function returns true to continue the mission.
	// Thus, only return true if they return false.
	if (lResult == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool GerikSpellsPythonIFace::continueSpellResults(CvSelectionGroup* pSelectedGroup, int iData1, int iData2, int iEncodedFlags)
{
	// Call the python function to do scripts based on when a spell is "activated"
	CySelectionGroup* pyGroup = new CySelectionGroup(pSelectedGroup);

	// We had to pass eSpell and iData1 encoded into the MissionData data struct, so we'll deencode it now.
	SpellTypes eSpell = NO_SPELL;
	int iFlags = -1;
	GerikSpellsUtils::deencodeFlagVariable(iEncodedFlags, eSpell, iFlags);

	FAssertMsg(eSpell >= 0, "getSpellFromDataVariable computed an illegal spell type");
	FAssertMsg(eSpell < GC.getNumSpellInfos(), "getSpellFromDataVariable computed an illegal spell type");
	
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(iData1);
	argsList.add(iData2);
	argsList.add(iFlags);

	long lResult = 0;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, CONTINUE_SPELL_RESULTS_FUNC_NAME, argsList.makeFunctionArgs(), &lResult);
	delete pyGroup;

	// This function returns true to delete the mission. The python function returns true to continue the mission.
	// Thus, only return true if they return false.
	if (lResult == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void GerikSpellsPythonIFace::cleanupSpell(CvSelectionGroup* pCastingGroup, int iData1, int iData2, int iEncodedFlags)
{
	// Call the python function to do scripts based on when a spell is "activated"
	CySelectionGroup* pyGroup = new CySelectionGroup(pCastingGroup);

	// We had to pass eSpell and iData1 encoded into the MissionData data struct, so we'll deencode it now.
	SpellTypes eSpell = NO_SPELL;
	int iFlags = -1;
	GerikSpellsUtils::deencodeFlagVariable(iEncodedFlags, eSpell, iFlags);

	FAssertMsg(eSpell >= 0, "getSpellFromDataVariable computed an illegal spell type");
	FAssertMsg(eSpell < GC.getNumSpellInfos(), "getSpellFromDataVariable computed an illegal spell type");
	
	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyGroup));
	argsList.add(iData1);
	argsList.add(iData2);
	argsList.add(iFlags);

	long lResult;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, CLEANUP_SPELL_FUNC_NAME, argsList.makeFunctionArgs(), &lResult);
	delete pyGroup;
}


void GerikSpellsPythonIFace::setSpellUnitHelpText(CvWString &szBuffer, const CvUnit* pUnit)
{
	SpellTypes eSpell = pUnit->getGroup()->getSpellNumber();
	
	// If the unit is not even doing a spell mission, don't do anything.
	if (eSpell == NO_SPELL)
	{
		return;
	}

	FAssertMsg(eSpell >= 0, "getSpellFromDataVariable computed an illegal spell type");
	FAssertMsg(eSpell < GC.getNumSpellInfos(), "getSpellFromDataVariable computed an illegal spell type");

	// We can't make a CyUnit with a const CvUnit, so we'll have to improvise.
	CyUnit* pyUnit = new CyUnit(GET_PLAYER(pUnit->getOwner()).getUnit(pUnit->getID()));

	CyArgsList argsList;
	argsList.add(eSpell);
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));

	CvString szResult;
	gDLL->getPythonIFace()->callFunction(GerikSpellsUtils::GERIK_SPELL_MODULE, GET_SPELL_UNIT_HELP_TEXT, argsList.makeFunctionArgs(), &szResult);
	delete pyUnit;

	// Convert into a wchar.
	// We couldn't get a wstring return, so the python side converts to utf8. We need to unconvert it...
	CvWString szWResult;
	GerikSpellsUtils::deencodeUtfToWideString(szResult, szWResult);
	szBuffer += szWResult;
}

